package com.sn.author.common.sdk.util;

import com.alibaba.fastjson.JSON;
import com.sn.author.common.sdk.AbstractResponse;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ObjectNode;

public class JsonParser implements Parser {

    private final ObjectMapper mapper = new ObjectMapper();

    public JsonParser() {
        this.mapper.getDeserializationConfig().set(DeserializationConfig.Feature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
        this.mapper.getDeserializationConfig().set(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        this.mapper.getDeserializationConfig().set(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    @Override
    public <T extends AbstractResponse> T parse(String json, Class<T> responseClass) throws Exception {
        AbstractResponse response;

        try {
            if (Utils.isEmpty(json)) {
                throw new Exception("response json is empty!");
            } else {
                response = this.fromJson(json, responseClass);
                return (T) response;
            }
        } catch (Exception e) {
            throw new Exception(e);
        }
    }

    private <T extends AbstractResponse> T fromJson(String json, Class<T> responseClass) throws Exception {
        ObjectNode rootNode;

        try {
            rootNode = (ObjectNode) this.mapper.readTree(json);
        } catch (Exception e) {
            rootNode = (ObjectNode) this.mapper.readTree(JSON.toJSONString(json));
        }

        String innerJson = this.mapper.writeValueAsString(rootNode);
        mapper.configure(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        return this.mapper.readValue(innerJson, responseClass);
    }
}
